/** @file    MediaDirectorParser.cpp
 *  @author  Alessandro Polo
 *  @version $Id: MediaDirectorParser.cpp 2808 2010-07-28 20:44:00Z alex $
 *  @brief
 * File containing methods for the MediaDirectorParser class.
 * The header for this class can be found in MediaDirectorParser.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include "MediaDirectorParser.h"

 #include <core/Message.h>
 #include <core/Request.h>
 #include <core/Response.h>
 #include <core/MethodsCommon.h>
 #include <core/Bundle.h>
 #include <core/UserManager.h>
 #include <core/NetworkManager.h>
 #include <core/List.h>
 #include <core/Table.h>

 #include <stdlib.h>
 #include <time.h>
 #include <algorithm>

using namespace std;
using namespace wosh;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

MediaDirectorParser::MediaDirectorParser( BundleGeneric& bundle, Map<string, MediaZone*>& Players, BusConnector& busDevices, BusConnector& busBuilding )
	: BundleGenericWorker(bundle), zones(Players), BusDevices(busDevices), BusBuilding(busBuilding)
 {
	this->listener = NULL;
	this->timeoutEval = 0;
 }


MediaDirectorParser::~MediaDirectorParser() {
	if ( isThreadRunning() ) {
		quitThread(10000);
	 }

 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////// RUN THREAD

void MediaDirectorParser::runThread()
 {
	Log(LOG_VERBOSE, ":runThread(): STARTING" );

	updateAll("*");

	long counterEval = 0;
	while( this->running )
	 {
		setThreadAlive();
		ThreadImpl::sleepForMSec(500);
		if ( !this->running ) break;
		setThreadAlive();
		ThreadImpl::sleepForMSec(500);

		if ( this->timeoutEval > 0 ) {
			++counterEval;
			if ( counterEval > this->timeoutEval ) {
				counterEval = 0;
updateAll("*");
				evalTimeOut();
			 }
		 }
	 }

	Log(LOG_VERBOSE, ":runThread(): EXITING" );
 }

////////////////////////////////////////////////////////////////////////////////////////////////// RUN THREAD
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::evalTimeOut()
 {
	Log(LOG_INFO, ":evalTimeOut(): Evaluating Timedout Players.." );

	long now = Utilities::std_time();
	// check for timed out communicators
	this->zones.mutex().lockForWrite();
	std::map<string, MediaZone*>::iterator it_c;
	std::map<string, MediaZone*>::iterator it_c_end = this->zones.stdEnd();
	for ( it_c=this->zones.stdBegin(); it_c!=it_c_end; it_c++ ) {
		if ( it_c->second == NULL ) continue;
		if ( it_c->second->isTypeStatic() ) continue;
		if ( now - it_c->second->getSeen() > 120 ) {
			Log(LOG_WARNING, ":evalTimeOut(): TimeOut Player %s", it_c->first.c_str() );
///@todo UPDATE IT
//			delete it_c->second;
//			this->zones.erase_(it_c);
			break;
		 }
	 }
	this->zones.mutex().unLock();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::evalMessageIncoming( const Message& message )
 {
	if ( message == NULL || message.isEmpty() ) return;

	// monitor new/removed hosts (to update remote Communicators)
	// monitor bundle state-changed/install/removal
	if ( message.getContent()->isFact() ) {
		const wosh::Fact* fact = message.getContent()->asFact();
		if ( message.getSource().getName() == "Network" ) {
			if ( fact->getEvent() == _NetworkManager_EVENT_WoshHostAdded || fact->getEvent() == _NetworkManager_EVENT_WoshHostConnected ) {
				if ( fact->hasData() && fact->getDataClassName() == Variant::className() ) {
					const wosh::Data* data = dynamic_cast<const wosh::Data*>(fact->getData());
					Log(LOG_VERBOSE, ":busMessage() : Host updated/added, Updating Players.." );
					updateAll( data->getData() );
				 }
				else if ( fact->hasData() && fact->getDataClassName() == WoshHost::className() ) {
					const wosh::WoshHost* host = dynamic_cast<const wosh::WoshHost*>(fact->getData());
					Log(LOG_VERBOSE, ":busMessage() : Host updated/added, Updating Players.." );
					updateAll( host->getName() );
				 }
			}
			else if ( fact->getEvent() == _NetworkManager_EVENT_WoshHostAdded || fact->getEvent() == _NetworkManager_EVENT_WoshHostDisconnected ) {
				Log(LOG_VERBOSE, ":busMessage() : Host disconnected/removed, Disabling Communicators.." );
			}
			return;
		 }
	 }

	if ( message.getContent()->isResponse() ) {
		const Response* response = message.getContent()->asResponse();
		if ( !response->hasData() ) return;
		if ( response->getMethod() == _METHOD_ListProperties ) {
			if ( !response->getData()->isKindOf<Table>() ) return;
			const wosh::Table* table = response->getData()->as<Table>();

			if ( message.getSourceBus() == _Bus_Devices )
				evalResponseDeviceProperties(table, message.getSource());
			else  if ( message.getSourceBus() == _Bus_Building )
				evalAudioBoxProperties(table, message.getSource());
			return;
		 }
		else if ( response->getMethod() == _BuildingManager_METHOD_getchildprop ) {
			if ( !response->getData()->isKindOf<Table>() ) return;
			const wosh::Table* propschildren = response->getData()->as<Table>();
			evalAudioBoxesProperties(propschildren, message.getSource());
			return;
		 }
		else if ( response->getMethod() == _METHOD_List ) {
			if ( !response->getData()->isKindOf<Table>() ) return;
//			const wosh::Table* listchildren = response->getData()->as<Table>();
	//		evalPlayerBuildingChildren_(listchildren, message.getSource());
			return;
		 }
	}

 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::updateAll( const string& kernel )
 {
	requestMultimediaDevices( kernel );
	requestAudioBoxesProperties( kernel );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

// request properties FOR EACH _PlayerAudio_TYPE device 
void MediaDirectorParser::requestMultimediaDevices( const string& kernel )
 {
	Message* message0 = new Message( new Request(_METHOD_ListProperties) );
	message0->setSource(this->getOwner());
	message0->setDestinationBus( _Bus_Devices );
	message0->getDestination().fromString(kernel+":**/*");
	message0->getDestination().getExpression().setPredicate(_Bundle_KEY_Interfaces, _PlayerAudio_TYPE, '~');
	BusDevices.postMessage(message0);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

// eval properties-Table of multimedia DEVICE (i.e. PlayerAudio),
// CREATE zone if missing, UPDATE playerInterfaces
void MediaDirectorParser::evalResponseDeviceProperties( const wosh::Table* props_of_device, const URI& uri_of_device )
 {
	this->zones.mutex().lockForWrite();
	MediaZone* zone = getZoneByDeviceUri_(uri_of_device);
	if ( zone == NULL ) {
		Log(LOG_INFO, ":evalResponseDeviceProperties_() : New Player device found [%s]", uri_of_device.toString().c_str() );
		zone = createZoneByDeviceUri_( uri_of_device );
		// we still miss: {Location; current state; hierarchy/relation with other zones}
		// to retrieve location and hierarchy we need info about BuildingObject referring
		// to this device (as an AudioBox)
		// let's investigate, requesting BuildingObject associated with this device
		requestAudioBoxProperties( "*", uri_of_device );
	 }

	zone->setSeen();
	if ( zone->getZoneType() == MediaZone::TYPE_STATIC ) {
		Log(LOG_INFO, ":evalResponseDeviceProperties_(%s) : Skipping Static Zone update [%s]", uri_of_device.getName().c_str(), zone->getName().c_str() );
		this->zones.mutex().unLock();
		return;
	 }
	Log(LOG_VERBOSE, ":evalResponseDeviceProperties_(%s) : Updating Device-Interfaces of Zone [%s]", uri_of_device.getName().c_str(), zone->getName().c_str() );

	for(unsigned int row=0; row<props_of_device->getRows(); row++ ) {
		const ISerializable* objName = props_of_device->get(row, 0);
		const ISerializable* objValue = props_of_device->get(row, 1);
		if ( objName == NULL || !objName->isKindOf<Variant>() ) continue;
		if ( objValue == NULL || !objValue->isKindOf<Variant>() ) continue;
		const wosh::Data* dataName = dynamic_cast<const wosh::Data*>(objName);
		const wosh::Data* dataValue = dynamic_cast<const wosh::Data*>(objValue);

		if ( dataName->getData() == _Bundle_KEY_Interfaces )
			zone->getInterfaces().fromString( dataValue->getData(), false ); // overwrite
		else if ( dataName->getData() == _Player_KEY_Volume )
			zone->setVolume( dataValue->toInteger() );
		else if ( dataName->getData() == _Player_KEY_Mute )
			zone->setMuted( dataValue->toBoolean(false) );

		else if ( dataName->getData() == _Player_KEY_State ) {
			///@todo eval if they are synch, else force update
		 }
	 }
	this->zones.mutex().unLock();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::requestAudioBoxesProperties( const string& kernel )
 {
	List* dl1 = new List(4);
	dl1->add( "type="_AudioBox_TYPE );
//dl1->add( "type="_AudioBox_TYPE";|type="_Room_TYPE );
	dl1->add( _KEY_type );
	dl1->add( _AudioBox_KEY_Device );
	dl1->add( _BuildingObject_KEY_Location );
	Message* message1 = new Message( new Request(_BuildingManager_METHOD_getchildprop, dl1) );
	message1->setSource(this->getOwner());
	message1->setDestinationBus( _Bus_Core );
	message1->getDestination().fromString(kernel+":Building");
	BusCore.postMessage(message1);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::evalAudioBoxesProperties( const wosh::Table* grouped_props, const URI& )
 {
	// this buildingobject is an abstraction of real device, it refers to a read media device
	// find or create the DEVICE media zone
	this->zones.mutex().lockForWrite();
	MediaZone* zone = NULL;
	string prev_uri;
	for(unsigned int row=0; row<grouped_props->getRows(); row++ ) {
		const ISerializable* objUri = grouped_props->get(row, 0);
		const ISerializable* objKey = grouped_props->get(row, 1);
		const ISerializable* objValue = grouped_props->get(row, 2);
		if ( objUri == NULL || !objUri->isKindOf<Variant>() ) continue;
		if ( objKey == NULL || !objKey->isKindOf<Variant>() ) continue;
		if ( objValue == NULL || !objValue->isKindOf<Variant>() ) continue;
		const wosh::Data* dataUri = dynamic_cast<const wosh::Data*>(objUri);
		const wosh::Data* dataKey = dynamic_cast<const wosh::Data*>(objKey);
		const wosh::Data* dataValue = dynamic_cast<const wosh::Data*>(objValue);

		if ( prev_uri != dataUri->getData() ) {
			prev_uri = dataUri->getData();
			zone = NULL;
		 }

		if ( dataKey->getData() == _AudioBox_KEY_Device ) {
			if ( dataValue->isEmpty() ) {
				zone = NULL;
				continue;
			 }
			URI deviceUri( dataValue->getData() );
			zone = getZoneByDeviceUri_(deviceUri);
			if ( zone == NULL ) {
				Log(LOG_INFO, ":evalAudioBoxProperties() : New Player device found [%s]", deviceUri.toString().c_str() );
				zone = createZoneByDeviceUri_( deviceUri );
			 }
		 }
		if ( zone == NULL ) continue;
		if ( zone->isTypeStatic() ) continue;

		if ( dataKey->getData() == _BuildingObject_KEY_Location ) {
			if ( !dataValue->getData().empty() || zone->isTypeDynamic() )
				zone->setLocationURI( dataValue->getData() );
			//string loc = dataValue->getData(); //remove name from location
			//pInfo->getLocationURI() = loc.substr(0, loc.find_last_of("/"));;
		 }

	 }
	this->zones.mutex().unLock();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::requestAudioBoxProperties( const string& kernel, const URI& device_uri )
 {
	Message* message0 = new Message( new Request(_METHOD_ListProperties) );
	message0->setSource(this->getOwner());
	message0->setDestinationBus( _Bus_Building );
	message0->getDestination().fromString(kernel+":**/*");
	message0->getDestination().getExpression().setPredicate(_KEY_type, _AudioBox_TYPE, '=');
	if ( device_uri.isEmpty() )
		message0->getDestination().getExpression().setPredicate(_AudioBox_KEY_Device, device_uri.toString(), '=');

	BusBuilding.postMessage(message0);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::evalAudioBoxProperties( const wosh::Table* props, const URI& )
 {
	// this buildingobject is an abstraction of real device, it refers to a read media device
	// find or create the DEVICE media zone
	MediaZone* zone = NULL;
	for(unsigned int row=0; row<props->getRows(); row++ ) {
		const ISerializable* objName = props->get(row, 0);
		if ( objName == NULL || !objName->isKindOf<Variant>() ) continue;
		const wosh::Data* dataName = dynamic_cast<const wosh::Data*>(objName);
		if ( dataName->getData() != _AudioBox_KEY_Device ) continue;
		const ISerializable* objValue = props->get(row, 1);
		if ( objValue == NULL || !objValue->isKindOf<Variant>() ) continue;
		const wosh::Data* dataValue = dynamic_cast<const wosh::Data*>(objValue);
		if ( dataValue->isEmpty() ) continue;

		this->zones.mutex().lockForWrite();
		URI deviceUri( dataValue->getData() );
		zone = getZoneByDeviceUri_(deviceUri);
		if ( zone == NULL ) {
			Log(LOG_INFO, ":evalAudioBoxProperties() : New Player device found [%s]", deviceUri.toString().c_str() );
			zone = createZoneByDeviceUri_( deviceUri );
		 }
		break;
	 }
	if ( zone == NULL ) {
		return;
	 }
	zone->setSeen();
	if ( zone->isTypeStatic() ) {
		this->zones.mutex().unLock();
		return;
	 }

	// let's update other fields: LOCATION! 
	for(unsigned int row=0; row<props->getRows(); row++ ) {
		const ISerializable* objName = props->get(row, 0);
		const ISerializable* objValue = props->get(row, 1);
		if ( objName == NULL || !objName->isKindOf<Variant>() ) continue;
		if ( objValue == NULL || !objValue->isKindOf<Variant>() ) continue;
		const wosh::Data* dataName = dynamic_cast<const wosh::Data*>(objName);
		const wosh::Data* dataValue = dynamic_cast<const wosh::Data*>(objValue);

		if ( dataName->getData() == _BuildingObject_KEY_Location ) {
			if ( !dataValue->getData().empty() || zone->isTypeDynamic() )
				zone->setLocationURI( dataValue->getData() );
			//string loc = dataValue->getData(); //remove name from location
			//pInfo->getLocationURI() = loc.substr(0, loc.find_last_of("/"));;
		 }
		else if ( dataName->getData() == _BuildingObject_KEY_State ) {
			///@todo eval if they are synch, else force update

		 }
	 }
	this->zones.mutex().unLock();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::requestRoomChildren( const string& kernel )
 {
	Message* message0 = new Message( new Request(_METHOD_List) );
	message0->setSource(this->getOwner());
	message0->setDestinationBus( _Bus_Building );
	message0->getDestination().fromString(kernel+":**/*");
	message0->getDestination().getExpression().setPredicate(_Bundle_KEY_Interfaces, _Room_TYPE, '~');
	BusBuilding.postMessage(message0);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::evalRoomChildren( const wosh::Table* children_of_room, const URI& )
 {
	this->zones.mutex().lockForWrite();
	for(unsigned int row=0; row<children_of_room->getRows(); row++ ) {
		const ISerializable* objName = children_of_room->get(row, 0);
		const ISerializable* objInterfaces = children_of_room->get(row, 1);
		if ( objName == NULL || !objName->isKindOf<Variant>() ) continue;
		if ( objInterfaces == NULL || !objInterfaces->isKindOf<Variant>() ) continue;
//		const wosh::Data* dataName = dynamic_cast<const wosh::Data*>(objName);
		const wosh::Data* dataInterfaces = dynamic_cast<const wosh::Data*>(objInterfaces);

		if ( dataInterfaces->getData().find(_AudioBox_TYPE) != string::npos ) {
			// so this Room has an audio box!

// QUERY AUDIO BOX

		 }
	 }
	this->zones.mutex().unLock();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
















// request properties (as single table) of TYPE..
void MediaDirectorParser::requestBuildingObjects( const string& kernel )
 {
	List* dl1 = new List(4);
	dl1->add( "type="_AudioBox_TYPE );
//dl1->add( "type="_AudioBox_TYPE";|type="_Room_TYPE );
	dl1->add( _KEY_type );
	dl1->add( _BuildingObject_KEY_Location );
	dl1->add( _AudioBox_KEY_Device );
	Message* message1 = new Message( new Request(_BuildingManager_METHOD_getchildprop, dl1) );
	message1->setSource(this->getOwner());
	message1->setDestinationBus( _Bus_Core );
	message1->getDestination().fromString(kernel+":Building");
	BusCore.postMessage(message1);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////









//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
 - location = device location property

DEVICE DEFINED
 - list of device by {,} interfaces
 - one zone foreach device
 - foreach device, update timestamp of its zone
 - remember ZONE_TYPE!

ROOM DEFINED
 - list of audiobox ...=> room, 
 - device is empty, interfaces = sum(children)
FLOOR DEFINED
 - list of floor and their children,
 - one zone x floor, IF HAS ROOMS already defined
 - define as zone-group (child-rooms)
 - device is empty, interfaces = sum(children)
HOME DEFINED
 - home is a zone
 - groups floors already defined
 - device is empty, interfaces = sum(children)

*/

void MediaDirectorParser::evalPlayerBuildingChildren_( const wosh::Table* childrenprops, const URI& )
 {
	this->zones.mutex().lockForWrite();
	for(unsigned int row=0; row<childrenprops->getRows(); row++ ) {
		const ISerializable* objName = childrenprops->get(row, 0);
		const ISerializable* objInterfaces = childrenprops->get(row, 1);
		if ( objName == NULL || !objName->isKindOf<Variant>() ) continue;
		if ( objInterfaces == NULL || !objInterfaces->isKindOf<Variant>() ) continue;
		const wosh::Data* dataURI = dynamic_cast<const wosh::Data*>(objName);
		const wosh::Data* dataInterfaces = dynamic_cast<const wosh::Data*>(objInterfaces);

		MediaZone* pInfo = this->zones.key_(dataURI->getData());
		if ( pInfo == NULL ) {
			Log(LOG_INFO, ":evalPlayerBuildingChildren_() : New Player found [%s]", dataURI->getData().c_str() );
			pInfo = new MediaZone();
//			pInfo->getURI().fromString(dataURI->getData());
//			pInfo->getBuildingObjectURI() = uri;
			this->zones.set_(pInfo->getURI().getName(), pInfo);
		 }

	 }

	this->zones.mutex().unLock();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::evalPlayerBuilding_( const wosh::Table* childrenprops, const URI& )
 {
	this->zones.mutex().lockForWrite();
	for(unsigned int row=0; row<childrenprops->getRows(); row++ ) {
		const ISerializable* objURI = childrenprops->get(row, 0);
		const ISerializable* objKey = childrenprops->get(row, 1);
		const ISerializable* objValue = childrenprops->get(row, 2);
		if ( objURI == NULL || !objURI->isKindOf<Variant>() ) continue;
		if ( objKey == NULL || !objKey->isKindOf<Variant>() ) continue;
		if ( objValue == NULL || !objValue->isKindOf<Variant>() ) continue;
		const wosh::Data* dataURI = dynamic_cast<const wosh::Data*>(objURI);
		const wosh::Data* dataKey = dynamic_cast<const wosh::Data*>(objKey);
		const wosh::Data* dataValue = dynamic_cast<const wosh::Data*>(objValue);

		MediaZone* pInfo = getPlayerByBuildingObj_( dataURI->getData() );
		if ( pInfo == NULL && dataKey->getData() == _AudioBox_KEY_Device  )
			pInfo = this->zones.key_( dataValue->getData() );

		if ( pInfo == NULL )
			continue;

		if ( dataKey->getData() == _BuildingObject_KEY_Location ) {
			string loc = dataValue->getData(); //remove name from location
			pInfo->getLocationURI() = loc.substr(0, loc.find_last_of("/"));;
		 }
		
	 }

	if ( this->listener != NULL ) {
		vector<string> locations;
		std::map<string, MediaZone*>::iterator it_c;
		std::map<string, MediaZone*>::iterator it_c_end = this->zones.stdEnd();
		for ( it_c=this->zones.stdBegin(); it_c!=it_c_end; it_c++ ) {
			if ( it_c->second == NULL ) continue;
			locations.push_back( it_c->second->getLocationURI() );
		 }
		this->listener->updateLocations( locations );
	 }

	this->zones.mutex().unLock();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaDirectorParser::evalPlayerDevice_( const wosh::Table* props, const URI& uri )
 {
	this->zones.mutex().lockForWrite();
	MediaZone* player = this->zones.key_( uri.getName() );
	if ( player == NULL ) {
		Log(LOG_INFO, ":evalPlayer_() : New Player found [%s]", uri.toString().c_str() );
		player = new MediaZone();
		player->getURI() = uri;
		this->zones.set_(uri.getName(), player);
	 }
	else
		Log(LOG_INFO, ":evalPlayer_() : Updating Player [%s]", uri.toString().c_str() );

	player->setSeen();
	for(unsigned int row=0; row<props->getRows(); row++ ) {
		const ISerializable* objName = props->get(row, 0);
		const ISerializable* objValue = props->get(row, 1);
		if ( objName == NULL || !objName->isKindOf<Variant>() ) continue;
		if ( objValue == NULL || !objValue->isKindOf<Variant>() ) continue;
		const wosh::Data* dataName = dynamic_cast<const wosh::Data*>(objName);
		const wosh::Data* dataValue = dynamic_cast<const wosh::Data*>(objValue);

		if ( dataName->getData() == _Bundle_KEY_Interfaces )
			player->getInterfaces().fromString( dataValue->getData() );
	 }
	this->zones.mutex().unLock();

	// get LOCATION of DEVICE
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

MediaZone* MediaDirectorParser::createZoneByDeviceUri_( const URI& uri_of_device )
 {
	string name = uri_of_device.getName();
	if ( name.find("Player") == 0 )
		name.erase(0, 6);
	name = "zone_" + name;
	MediaZone* zone = new MediaZone();
	zone->setName(name);
	zone->getURI().setParent(this->getOwner()->getURI());
	zone->getURI().setName(name);
	zone->setPermission(this->getOwner()->getPermission());
	zone->setZoneType(MediaZone::TYPE_DYNAMIC);
	zone->setPlayerURI(uri_of_device);
	zone->setSeen();
	this->zones.set_(name, zone);
	return zone;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

MediaZone* MediaDirectorParser::getZoneByDeviceUri_( const URI& device_uri )
 {
	std::map<string, MediaZone*>::const_iterator it_c;
	std::map<string, MediaZone*>::const_iterator it_c_end = this->zones.stdEnd();
	for ( it_c=this->zones.stdBegin(); it_c!=it_c_end; it_c++ ) {
		if ( it_c->second == NULL ) continue;
		if ( it_c->second->getPlayerURI() != device_uri ) continue;
		return it_c->second;
	 }
	return NULL;
 }

MediaZone* MediaDirectorParser::getPlayerByBuildingObj_( const string& bobjUri )
 {
	std::map<string, MediaZone*>::const_iterator it_c;
	std::map<string, MediaZone*>::const_iterator it_c_end = this->zones.stdEnd();
	for ( it_c=this->zones.stdBegin(); it_c!=it_c_end; it_c++ ) {
		if ( it_c->second == NULL ) continue;
//		if ( it_c->second->getBuildingObjectURI() != bobjUri ) continue;
//		return it_c->second;
	 }
	return NULL;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*

WRESULT MediaDirectorParser::loadObjects()
 {
	FilePath xmlFile;
	if ( !xmlFile.set( Properties.getValueOf(_MediaDirector_KEY_DB).getData() ) ) {
		SystemError::raise(this, Log, SystemError::CRITICAL, 0, "loadObjects", "FAILED#1 Invalid Archive File [%s]", xmlFile.getPath().c_str() );
		return WRET_ERR_PARAM;
	 }
	if ( !xmlFile.exists() ) {
		SystemError::raise(this, Log, SystemError::CRITICAL, 0, "loadObjects", "FAILED#1 Archive File doesn't exists %s [%s]!", xmlFile.getPath().c_str(), xmlFile.getPathLocal().c_str() );
		return WRET_ERR_PARAM;
	 }
	// may also be a folder of .xml files
	Log(LOG_VERBOSE, ":loadObjects() File %s ..", xmlFile.getPathLocal().c_str() );

	return ret;
 }
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
